home *** CD-ROM | disk | FTP | other *** search
/ Freaks Macintosh Archive / Freaks Macintosh Archive.bin / Freaks Macintosh Archives / PC / EDACS.ZIP / EDACS.C next >
C/C++ Source or Header  |  1997-12-28  |  28KB  |  759 lines

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <conio.h>
  4. #include <dos.h>
  5. #include <stdlib.h>
  6. #include <math.h>
  7.  
  8. /* EDACS control channel monitoring program... */
  9.  
  10.  
  11. /* Scanner / system specific stuff needed for "trunk tracking" mode   */
  12.  
  13. static double baudrate=1200.0;/* baud rate of computer to scanner link*/
  14.  
  15. /* This is the table equating logical channel numbers with actual     */
  16. /* frequencies. The first entry, chan[0], gives the frequency for     */
  17. /* logical channel number 1; chan[1] give the frequency for LCN 2,    */
  18. /* et cetera. You will need to change this table to match those       */
  19. /* systems in your own area unless you happen to live in Huntsville   */
  20. /* Alabama and want to monitor this 5 channel commercial SMR trunk    */
  21. static double chan[30] = {
  22.   856.0375, 857.0375, 858.0375, 859.0375, 860.0375
  23. };
  24. /* this identifies the control channel in the above table             */
  25. int control = 1; /* this number is the lcn of the control channel - 1 */
  26. int nucha  = 20; /* number of channels in system; for the above       */
  27.                  /* system it should be set to five, but it was put to*/
  28.                  /* 20 for people who don't want to change the default*/
  29.  
  30.  
  31. /*                    global variables                                */
  32. int lc=0;
  33. int fobp=0;    /* pointer to current position in array fob          */
  34. char ob[1000];  /* buffer for raw data frames                         */
  35. int obp=0;    /* pointer to current position in array ob              */
  36. int invfla = 0; /* bit inversion flag                                 */
  37. static int comport = 0x3f8;   /* serial port base address; set in main*/
  38. static int sport = 1;         /* serial port number to use            */
  39.  
  40. static int dotting = 0;       /* dotting sequence detection flag      */
  41. static int mode = 0;          /* mode flag; 0 means we're on control  */
  42.                   /* channel; 1 means active frequency    */
  43.  
  44. /* array for raw data coming off the serial port              */
  45. static unsigned int buflen= 15000;      /* length of data buffer      */
  46. static volatile unsigned int cpstn = 0; /* current position in buffer */
  47. static volatile unsigned int fdata[15001] ; /* timing data array      */
  48.  
  49. void interrupt (*oldfuncc) (); /* vector to old com port interrupt    */
  50.  
  51.  
  52. /*--------------------------------------------------------------------*/
  53. /*           A BUNCH OF LOW LEVEL STUFF FOLLOWS                       */
  54. /*--------------------------------------------------------------------*/
  55. /**********************************************************************/
  56. /*                            comint                                  */
  57. /*                                                                    */
  58. /*               this is serial com port interrupt                    */
  59. /* we assume here that it only gets called when one of the status     */
  60. /* lines on the serial port changes (that's all you have hooked up).  */
  61. /* All this handler does is find the number of system timer ticks     */
  62. /* since the last call and stores it in the fdata array. The MSB      */
  63. /* is set to indicate whether the status line is zero. In this way    */
  64. /* the fdata array is continuously updated with the appropriate       */
  65. /* length and polarity of each data pulse for further processing by   */
  66. /* the main program.                              */
  67. void interrupt comint()
  68. {
  69.   static unsigned int d1,d2,ltick,tick,dtick;
  70.  
  71.   /* the system timer is a 16 bit counter whose value counts down     */
  72.   /* from 65535 to zero and repeats ad nauseum. For those who really  */
  73.   /* care, every time the count reaches zero the system timer           */
  74.   /* interrupt is called (remember that thing that gets called every  */
  75.   /* 55 milliseconds and does housekeeping such as checking the       */
  76.   /* keyboard.                                                        */
  77.   outportb (0x43, 0x00);       /* latch counter until we read it      */
  78.   d1 = inportb (0x40);         /* get low count                       */
  79.   d2 = inportb (0x40);         /* get high count                      */
  80.  
  81.   /* get difference between current, last counter reading             */
  82.   tick  = (d2 << 8) + d1;
  83.   dtick = ltick - tick;
  84.   ltick = tick;
  85.  
  86.   /* set MSB to reflect state of input line */
  87.   if ((inportb(comport + 6) & 0xF0) > 0) dtick = dtick | 0x8000;
  88.                   else dtick = dtick & 0x3fff;
  89.  
  90.   fdata[cpstn] = dtick;        /* put freq in fdata array             */
  91.   cpstn  ++;                   /* increment data buffer pointer       */
  92.   if (cpstn>buflen) cpstn=0;   /* make sure cpstn doesnt leave array  */
  93.  
  94.   d1 = inportb (comport + 2);   /* clear IIR                           */
  95.   d1 = inportb (comport + 5);   /* clear LSR                           */
  96.   d1 = inportb (comport + 6);   /* clear MSR                           */
  97.   d1 = inportb (comport);       /* clear RX                            */
  98.   outportb (0x20, 0x20);       /* this is the END OF INTERRUPT SIGNAL */
  99. }
  100.  
  101. /************************************************************************/
  102. /*                  SERIAL PORT INITIALIZATION                          */
  103. /************************************************************************/
  104. /* basic purpose: enable modem status interrupt and set serial port     */
  105. /*          output lines to supply power to interface             */
  106. void set8250 (double bps)   /* sets up the 8250 UART               */
  107. {
  108.   static unsigned int t,dv,tp;
  109.  
  110.   dv = (int) 1843200.0/(16.0*bps);
  111.   /* how to configure your serial port setup:          */
  112.   /* do you want two stop bits? then make sure you set bit 2 in tp */
  113.   /* do you want a parity bit generated? then set bit bit 3 in tp  */
  114.   /* do you want even parity? then set bit 4 in tp                 */
  115.   /* do you want an 8 bit word length? set bits 0 and 1 in tp      */
  116.   /* do you want an 7 bit word length? set bit  1 in tp            */
  117.   tp = 0x80 + 0x02 + 0x01;
  118.   outportb (comport+3, tp);  /* set line control register  */
  119.   outport  (comport  , dv);  /* output brg divisor latch   */
  120.   tp = tp & 0x7f;            /* switch out brg divisor reg */
  121.   outportb (comport+3, tp);
  122.  
  123.  
  124.   outportb (comport+1, 0x08);  /*  enable MODEM STATUS INTERRUPT      */
  125.   outportb (comport+4, 0x0a);  /*  push up RTS, DOWN DTR              */
  126.   t = inportb(comport + 5);    /*  clear LSR                          */
  127.   t = inportb(comport);        /*  clear RX                           */
  128.   t = inportb(comport + 6);    /*  clear MSR                          */
  129.   t = inportb(comport + 2);    /*  clear IID                          */
  130.   t = inportb(comport + 2);    /*  clear IID - again to make sure     */
  131. }
  132.  
  133. /* this routine allows the RTS output line to be set either high or   */
  134. /* low depending on whether sta = 0.                                  */
  135. void rts_state(int sta)
  136. {
  137.   static int rv;
  138.   rv = inportb(comport + 4);
  139.   rv = rv & 0x01;  /* save DTR state                */
  140.   rv = rv | 0x08;  /* enable interrupt to reach PIC */
  141.   if (sta != 0) rv = rv | 0x02;
  142.   outportb(comport + 4, rv);
  143. }
  144.  
  145. /* this routine allows the DTR output line to be set either high or   */
  146. /* low depending on whether sta = 0.                                  */
  147. void dtr_state(int sta)
  148. {
  149.   static int rv;
  150.   rv = inportb(comport + 4);
  151.   rv = rv & 0x02;  /* save RTS state                     */
  152.   rv = rv | 0x08;  /* make sure interrupts can reach PIC */
  153.   if (sta != 0) rv = rv | 0x01;
  154.   outportb(comport + 4, rv);
  155. }
  156.  
  157.  
  158. /************************************************************************/
  159. /*                         send_char                                    */
  160. /*                                                                      */
  161. /* This routine sends a character out on the serial port TxD line.      */
  162. /* It makes sure the previous character has been completely sent and    */
  163. /* then sends puts the current character into the transmit register.    */
  164. /************************************************************************/
  165. void send_char(int c)
  166. {
  167.   /* wait for transmit reg to empty */
  168.   while ( (inportb(comport+0x05) & 0x20) == 0x00);
  169.  
  170.   /* send character */
  171.   outportb(comport,c);
  172. }
  173.  
  174.  
  175.  
  176. /************************************************************************/
  177. /*                         set_freak                                    */
  178. /*                                                                      */
  179. /* This routine must be written by the user for his/her specific radio. */
  180. /* The input is the desired frequency the scanner should go to.         */
  181. /* Characters are sent to the scanner using the send_char routine.      */
  182. /************************************************************************/
  183. void set_freak(double freq)
  184. {
  185.    /* put your code here */
  186.    /* call send_char() to send a byte to your scanner */
  187.  
  188. }
  189.  
  190.  
  191.  
  192. /************************************************************************/
  193. /*                    TIMER CHIP INITIALIZATION                         */
  194. /************************************************************************/
  195. /* purpose: make sure computer timekeeper is set up properly. This      */
  196. /*          routine probably isn't necessary - it's just an insurance   */
  197. /*        policy.                                                     */
  198. void set8253()                   /*  set up the 8253 timer chip         */
  199. {                                /* NOTE: ctr zero, the one we are using*/
  200.                                  /*  is incremented every 840nSec, is   */
  201.                                  /*  main system time keeper for dos    */
  202.   outportb (0x43, 0x34);         /* set ctr 0 to mode 2, binary         */
  203.   outportb (0x40, 0x00);         /* this gives us the max count         */
  204.   outportb (0x40, 0x00);
  205. }
  206.  
  207. /**********************************************************************/
  208. /*               higher level stuff follows                           */
  209. /**********************************************************************/
  210.  
  211. /* structure for storing the control channel data frame information  */
  212. struct ccdat{
  213.    int cmd;  /* command */
  214.    int lcn;  /* logical channel number */
  215.    int stat; /* status bits */
  216.    int id;   /* agency/fleet/subfleet id */
  217.    int bad;  /* CRC check flag - when set to 1 it means data is corrupt */
  218. };
  219.  
  220. /* array acn[] indicates which channels are currently active; aid[]  */
  221. /* indicates which id is using the active channel                    */
  222. /* acn[] is actually a countdown timer decremented each time a       */
  223. /* control channel command is received and is reset whenever that    */
  224. /* channel appears in control channel data stream. When this reaches */
  225. /* zero the channel is assumed to have become inactive.              */
  226. /* aid[] is used to make sure a new group appearing on an active     */
  227. /* channel is recognized even if acn[] had not yet reached zero      */
  228. int acn[33],aid[33],nacn=0;
  229.  
  230. /************************************************************************/
  231. /*                          show_setup                                  */
  232. /*                                                                      */
  233. /* Purpose: setup things for screen display                         */
  234. /************************************************************************/
  235. void show_setup()
  236. {
  237.   static int i;
  238.   clrscr();
  239.   for (i=0; i<33; i++) { acn[i] = 0; aid[i] = 0xffff; }
  240.   gotoxy(1,1);
  241.   textcolor(YELLOW);
  242.   cprintf("LCN  ID  ST    COMMAND");
  243.   gotoxy(1,2);
  244.   cprintf("--- ---- ---  ---------");
  245.   textcolor(LIGHTGRAY);
  246.   gotoxy(65,2);
  247.   cprintf("Using COM%1i",sport);
  248.   gotoxy(63,3);
  249.   cprintf("# channels: %2i",nucha);
  250.   gotoxy(60,4);
  251.   cprintf("Exit: Space or Esc ");
  252.   gotoxy(60,6);
  253.   cprintf("Misc Control data");
  254.   gotoxy(60,7);
  255.   cprintf("LCN   ID  ST  CMD");
  256.   gotoxy(75,1);
  257.   textcolor(WHITE);
  258.   cprintf("-");
  259.   nacn=0;
  260. }
  261.  
  262. /************************************************************************/
  263. /*                          show_active                                 */
  264. /*                                                                      */
  265. /* this routine gets called ONCE whenever a new ID becomes active on    */
  266. /* a given channel number                                               */
  267. /************************************************************************/
  268. void show_active(struct ccdat info)
  269. {
  270.   static int linx,liny,cm;
  271.  
  272.   /* this is where you will want to insert some code that decides if   */
  273.   /* you want to switch to this particular active frequency. Right     */
  274.   /* now this commented out code fragment would have sent your scanner */
  275.   /* off to any active frequency.                                      */
  276.   /* you'll probably also want to filter out data channel assignemnts  */
  277. /*  set_freak(chan[info.lcn-1]);    */
  278. /*  mode = 1;                       */
  279. /*  dotting = 0;                    */
  280.  
  281.   linx = 1;
  282.   liny = 2 + info.lcn;
  283.  
  284.   if (liny > 22)
  285.   {
  286.     linx = 31;
  287.     liny -= 20;
  288.   }
  289.  
  290.   gotoxy(linx,liny);
  291.   cm = info.cmd;
  292.   cprintf("%2i:  %03X  %01X   %02X ",info.lcn,info.id,info.stat,cm);
  293.   textcolor(LIGHTGRAY);
  294.   if (cm == 0xEE) cprintf ("VOICE");
  295.   else if (cm == 0xEC) cprintf ("PHONE");
  296.   else if (cm == 0xF6) cprintf ("VOICE");
  297.   else if (cm == 0xA0) cprintf ("DATA");
  298.   else if (cm == 0xA1) cprintf ("DATA");
  299.   textcolor(WHITE);
  300. }
  301.  
  302. /************************************************************************/
  303. /* show_inactive gets called when a channel is no longer active         */
  304. /* it simply writes out a bunch of spaces to erase the old              */
  305. /* information                                                          */
  306. /************************************************************************/
  307. void show_inactive(int lcn)
  308. {
  309.   static int linx,liny;
  310.   linx = 4;
  311.   liny = 2 + lcn;
  312.  
  313.   if (liny > 22)
  314.   {
  315.     linx = 34;
  316.     liny -= 20;
  317.   }
  318.  
  319.  
  320.   gotoxy(linx,liny);
  321.   aid[lcn] = 0xffff;
  322.   cprintf("                    ");
  323.  
  324. }
  325.  
  326. /* scroll raw commands on window in right hand side of display */
  327. void show_raw(struct ccdat inf)
  328. {
  329.   static int lc=8;
  330.   if (lc == 24) movetext(60,9,79,24,60,8);
  331.   else lc++;
  332.   gotoxy(61,lc);
  333.   cprintf("%02X  %03X   %01X   %02X",inf.lcn,inf.id,inf.stat,inf.cmd);
  334. }
  335.  
  336. /************************************************************************/
  337. /*                        proc_cmd                                      */
  338. /*                                                                      */
  339. /* This routine figures out when a group becomes active on a new        */
  340. /* channel and when a channel is has become inactive. This info is      */
  341. /* passed to the two routines above which show the changes on the       */
  342. /* screen                                                               */
  343. /************************************************************************/
  344. void show(struct ccdat info)
  345. {
  346.   static int idup=0,cdup=0,i,aid[8],sysid=0x0000;
  347.   static char dup[4] = { 45 , 47 , 124 , 92};
  348.  
  349.   /* update the "I'm still receiving data" spinwheel character on screen
  350. */  cdup++;  if (cdup > 9)  {  gotoxy(75,1);  idup = (idup + 1) & 0x03; 
  351. putch(dup[idup]);  cdup = 0;  }
  352.  
  353.   /* process only good information blocks  */
  354.   if (info.bad == 0)
  355.   {
  356.     /* try to display all non idle information blocks */
  357.     if (info.cmd < 0x80)
  358.     {
  359.       show_raw(info);
  360.     }
  361.     else if ( ((info.cmd >> 1) != 0x7E) )
  362.     {
  363.       if ( (info.lcn > 0) & (info.lcn <= nucha) )
  364.       {
  365.     /* check to see if ID is in active list... if not it must be new */
  366.     if ( aid[info.lcn] != info.id)
  367.     {
  368.  
  369. /*        if (aid[info.lcn] != 0xffff) show_inactive(info.lcn); */
  370.       /* a new ID has become active */
  371.       show_active(info);
  372.       /* add to activity list */
  373.       aid[info.lcn] = info.id;
  374.     }
  375.     /* update activity timer for this active channel */
  376.     acn[info.lcn] = 8 + (nacn << 2);
  377.       }
  378.     }
  379.     else if (info.cmd == 0xFD)
  380.     {
  381.       /* look at background / idle stuff to find system id */
  382.       if (sysid != info.id)
  383.       {
  384.     sysid = info.id;
  385.     textcolor(YELLOW);
  386.     gotoxy(35,1);
  387.     cprintf("SYS ID: %03X",sysid);
  388.     textcolor(WHITE);
  389.       }
  390.     }
  391.   }
  392.  
  393.   /* see if any channel numbers have dropped off */
  394.   /* this is done by waiting for a certain number of control channel */
  395.   /* commands to go by before assuming the channel is no longer      */
  396.   /* active.                                                         */
  397.   nacn = 0;  /* nacn holds the number of active channels */
  398.   for (i=1; i<=nucha; i++)
  399.   {
  400.     if (acn[i] != 0)
  401.     {
  402.       nacn++;
  403.       acn[i]--;
  404.       if (acn[i] == 0)
  405.       {
  406.     /* LCN has become inactive */
  407.     show_inactive(i);
  408.     aid[i] = 0xffff;
  409.  
  410.       }
  411.     }
  412.   }
  413.  
  414. }
  415.  
  416. /************************************************************************/
  417. /*                        proc_cmd                                      */
  418. /*                                                                      */
  419. /* This routine processes a data frame by checking the CRC and nicely   */
  420. /* formatting the resulting data into structure info                    */
  421. /************************************************************************/
  422. void proc_cmd(int c)
  423. {
  424.   static int ecc=0,sre=0,cc=0,ud=0xA9C,nbb=0,tb,orf,i;
  425.   static char oub[50];
  426.   static struct ccdat info;
  427.   if (c < 0)
  428.   {
  429.     cc = 0;
  430.     sre = 0x7D7;
  431.     ecc = 0x000;
  432.     oub[28] = 0;
  433.  
  434.     /* pick off, store  command   (eight bits) */
  435.     for (i=0; i<=7; i++)
  436.     {
  437.       orf = orf << 1;
  438.       orf += oub[i];
  439.     }
  440.     orf = orf & 0xff;
  441.     info.cmd = orf;
  442.  
  443.     /* pick off LCN   (five bits)  */
  444.     for (i=8; i<=12; i++)
  445.     {
  446.       orf = orf << 1;
  447.       orf += oub[i];
  448.     }
  449.     orf = orf & 0x1f;
  450.     info.lcn = orf;
  451.  
  452.     /* pick off four status bits */
  453.     for (i=13; i<=16; i++)
  454.     {
  455.       orf = orf << 1;
  456.       orf+=oub[i];
  457.     }
  458.     orf = orf & 0x0f;
  459.     info.stat = orf;
  460.  
  461.     /* pick off 11 ID bits    */
  462.     for (i=17; i<=27; i++)
  463.     {
  464.       orf = orf << 1;
  465.       orf+=oub[i];
  466.     }
  467.     orf = orf & 0x07ff;
  468.     info.id = orf;
  469.  
  470.     if (nbb == 0) info.bad = 0; else info.bad = 1;
  471.  
  472.     if (nbb == 0)
  473.     {
  474.       show(info);
  475.     }
  476.  
  477.     nbb = 0;
  478.   }
  479.   else
  480.   {
  481.  
  482.     cc++;
  483.     /* bits 1 through 28 will be run through crc routine */
  484.     if (cc <29)
  485.     {
  486.       oub[cc-1] = c;
  487.       if ( c == 1) ecc = ecc ^ sre;
  488.       if ( (sre & 0x01) > 0) sre = (sre >> 1) ^ ud; else sre = sre >> 1;
  489.     }
  490.     else
  491.     {
  492.       /* for the rest of the bits - check if they match calculated crc */
  493.       /* and keep track of the number of wrong bits in variable nbb    */
  494.       if ( (ecc & 0x800) > 0) tb = 1; else tb = 0;
  495.       ecc = (ecc << 1) & 0xfff;
  496.       if (tb != c) nbb++;
  497.     }
  498.   }
  499. }
  500.  
  501. /************************************************************************/
  502. /*                        proc_frame                                    */
  503. /*                                                                      */
  504. /* This routine processes the two raw data frames stored in array ob[]. */
  505. /* Each data frame is repeated three times with the middle repetition   */
  506. /* inverted. So bits at offsets of 0, 40, and 80 should all be carrying */
  507. /* the same information - either 010 or 101 if no errors have occured). */
  508. /* Error correction is done by ignoring any single wayward bit in each  */
  509. /* triplet. For example a 000 triplet is assumed to have actually been  */
  510. /* a 010; a 001 -> 101; 011 -> 010; et cetera. Array tal[] holds a table*/
  511. /* giving the "corrected" bit value for every possible triplet. Two     */
  512. /* or three wrong bits in a triplet cannot be corrected. The resulting  */
  513. /* data bits are send on the proc_cmd routine for the remaining         */
  514. /* processing.                                                          */
  515. /************************************************************************/
  516. void proc_frame()
  517. {
  518.   static int i,l;
  519.   static int tal[9]={0,1,0,0,1,1,0,1};
  520.  
  521.   /* do the first data frame */  proc_cmd(-1);    /* reset proc_cmd routine
  522. */  for (i=0; i<40; i++)  {  l = (int) ( (ob[i]<<2) + (ob[i+40]<<1) +
  523. ob[i+80]);  /* form triplet */    l = tal[l];      /* look up the correct
  524. bit value in the table */  proc_cmd(l);  /* send out bit */  }
  525.  
  526.   /* do the second data frame */
  527.   proc_cmd(-2);
  528.   for (i=0; i<40; i++)
  529.   {
  530.     l = (int) ( (ob[i+120]<<2) + (ob[i+160]<<1) + ob[i+200]);
  531.     l = tal[l];
  532.     proc_cmd(l);
  533.   }
  534.  
  535. }
  536.  
  537.  
  538. /************************************************************************/
  539. /*                       frame_sync                    */
  540. /*                                    */
  541. /* This routine takes the raw bit stream and tries to find the 48 bit   */
  542. /* frame sync sequence. When found it stores the next 240 raw data bits */
  543. /* that make up a data frame and stores them in global array ob[].      */
  544. /* Routine proc_frame is then called to process the data frame and the  */
  545. /* cycle starts again. When mode = 1 it will only look for the dotting  */
  546. /* sequence and updat the dotting flag.                                 */
  547. /************************************************************************/
  548. void frame_sync(char gin)
  549. {
  550.   static int sr0=0,sr1=0,sr2=0,hof = 300,xr0,xr1,xr2,i,nh=0,ninv=0;
  551.   static int fsy[3][3]={
  552.        0x1555,0x5712,0x5555,   /* control channel frame sync            */
  553.        0x5555,0x5555,0x5555,   /* dotting sequence                      */
  554.        0xAAAA,0xAAAA,0x85D3    /* data channel frame sync (not used)    */
  555.   };
  556.  
  557.   /* update registers holding 48 bits */
  558.   sr0 = sr0 << 1;
  559.   if ( (sr1 & 0x8000) != 0) sr0 = sr0 ^ 0x01;
  560.   sr1 = sr1 << 1;
  561.   if ( (sr2 & 0x8000) != 0) sr1 = sr1 ^ 0x01;
  562.   sr2 = sr2 << 1;
  563.   sr2 = sr2 ^ (int) gin;
  564.  
  565.   /* update ob array */
  566.   if (obp <600)
  567.   {
  568.     ob[obp] = gin;
  569.     obp++;
  570.   }
  571.  
  572.   /* find number of bits not matching sync pattern */
  573.   xr0 = sr0 ^ fsy[mode][0];
  574.   xr1 = sr1 ^ fsy[mode][1];
  575.   xr2 = sr2 ^ fsy[mode][2];
  576.   nh = 0;
  577.   for (i=0; i<16; i++)
  578.   {
  579.     if ( (xr0 & 0x01) > 0) nh++; xr0 = xr0 >> 1;
  580.     if ( (xr1 & 0x01) > 0) nh++; xr1 = xr1 >> 1;
  581.     if ( (xr2 & 0x01) > 0) nh++; xr2 = xr2 >> 1;
  582.   }
  583.  
  584.   /* if there are less than 3 mismatches with sync pattern and we aren't
  585. */  /* inside a data frame (hold-off counter less than 288) sync up  */ 
  586. if ( nh < 4)  {  /* mode zero means we're monitoring control channel */ 
  587. if ( (hof > 287) && (mode == 0) )  {  proc_frame();  obp = 0;  hof = 0; 
  588. ninv = 0;  }  /* mode 1 means we're on voice channel and so we just found
  589. dotting */  else if ((mode == 1) && (nh < 2) )    {  dotting++;  }  }
  590.  
  591.   /* check for polarity inversion - if all frame sync bits mismatch 12  */
  592.   /* times in a row without ever getting a good match assume that one   */
  593.   /* must invert the bits                                               */
  594.   if ((nh == 48) && (mode == 0))
  595.   {
  596.     ninv++;
  597.     if (ninv > 12)
  598.     {
  599.       invfla ^= 0x01;
  600.       gotoxy (65,1);
  601.       if (invfla == 1) cprintf("INVERT"); else cprintf("      ");
  602.       ninv = 0;
  603.     }
  604.   }
  605.  
  606.   if (hof < 1000) hof++;
  607.  
  608. }
  609.  
  610. /************************************************************************/
  611. /*                         DISPLAY HELP SCREEN                          */
  612. /************************************************************************/
  613. void help()
  614. {
  615.   printf("\n  EDACS control channel monitoring program\n");
  616.   printf("     Command line arguement summary\n\n");
  617.   printf("  /NC:x       - set x to number of channels used in system you \n");
  618.   printf("                are monitoring. Minimum value = 3; max = 31    \n");
  619.   printf("  /COM:y      - set y = 1,2,3,4 to set com port you want to use.\n");
  620.   printf("\nExample: if your program is called edacs.exe and you wish to  \n");
  621.   printf("         monitor a 10 channel system using COM2 you should type \n");
  622.   printf("         the following in at the DOS prompt:\n\n");
  623.   printf("             EDACS /nc:10 /com:2\n");
  624.   printf("\n Interface requirements: Hamcomm type data slicer circuit.\n");
  625.   printf(" The program automatically determines the property polarity of \n");
  626.   printf(" the incoming data. When everything is working properly you will\n");
  627.   printf(" see the the character on the upper right hand corner of your \n");
  628.   printf(" screen spinning around indicating that EDACS control channel \n");
  629.   printf(" information is being successfully processed.\n\n");
  630.   printf(" See text file for further details...\n\n");
  631.   printf(" press any key to continue...\n");
  632.   getch();
  633. }
  634.  
  635.  
  636. void main (int argc,char *argv[],char *env[])
  637. {
  638.   static unsigned int n,i=0,j;
  639.   static int irqv = 0x0c,ef=0,ch;
  640.   FILE *out;
  641.   static char s=48,temp[20];
  642.   static double dt,exc=0.0,clk=0.0,xct,dto2;
  643.  
  644.   for (n=1; n<argc; n++)
  645.   {
  646.     strcpy(temp,argv[n]);
  647.     strupr(temp);
  648.     j+=sscanf(temp,"/NC:%i",&nucha);
  649.     j+=sscanf(temp,"/COM:%i",&sport);
  650.     if (temp[1] == 'H') j=30;
  651.   }
  652.  
  653.   if (nucha >31) { nucha = 31; j = 30; }
  654.   if (nucha < 3) { nucha = 3;  j = 30; }
  655.   if (sport > 4) { sport = 4;  j = 30; }
  656.   if (sport < 1) { sport = 1;  j = 30; }
  657.  
  658.   if ( (j+1) != argc) help();
  659.  
  660.  
  661.   clrscr();
  662.  
  663.   /* dt is the number of expected clock ticks per bit */
  664.   dt =  1.0/(9600.0*838.22e-9);
  665.   dto2 = 0.5*dt;
  666.  
  667.   /* set up items related to serial port                                */
  668.   n = inportb (0x21);
  669.   if ( (sport == 1) | (sport == 3))
  670.   {
  671.     irqv = 0x0c;
  672.     oldfuncc = getvect(irqv);    /* save COM  Vector                    */
  673.     setvect (irqv, comint);     /* Capture COM  vector                 */
  674.     outportb(0x21, n & 0xef);
  675.     if (sport == 1) comport = 0x3f8; else comport = 0x3e8;
  676.   }
  677.   else
  678.   {
  679.     irqv = 0x0b;
  680.     oldfuncc = getvect(irqv);    /* save COM  Vector                    */
  681.     setvect (irqv, comint);     /* Capture COM  vector                 */
  682.     outportb(0x21, n & 0xf7);
  683.     if (sport == 2) comport = 0x2f8; else comport = 0x2e8;
  684.   }
  685.  
  686.   set8253();                   /* set up 8253 timer chip              */
  687.  
  688.   set8250(baudrate);           /* set up 8250 UART                    */
  689.  
  690.   printf("Checking for data coming in on COM%i... \n",sport);
  691.   printf("If program just sits here press any key to exit...\n");
  692.   while ( (cpstn < 3) & (kbhit() == 0) );
  693.   if (cpstn < 3)  {
  694.       printf("HEY - no data seems to be coming in over your interface.\n\n");
  695.       outportb (0x21, n);  /* disable IRQ interrupt  */
  696.       setvect (irqv, oldfuncc);  /* restore old COM Vector */
  697.       exit(1);
  698.   }  else
  699.   printf("Interface seems to work properly...\n\n");
  700.  
  701.   if (nucha >31) nucha = 31;
  702.   if (nucha < 3) nucha = 3;
  703.  
  704.   show_setup();
  705.       
  706.   while (ef == 0)
  707.   {
  708.  
  709.    /* check if key has been hit */
  710.    if (kbhit() != 0)
  711.    {
  712.      ch = getch();
  713.      /* a space or Esc key press sets the exit flag */
  714.      if ((ch == 32) | (ch == 27)) ef = 1;
  715.      else
  716.      {
  717.        /* any other key press returns the scanner to the control */
  718.        /* channel if it had switched to an active channel        */
  719.        set_freak(chan[control]);
  720.        mode = 0;
  721.        i = cpstn;
  722.      }
  723.    }
  724.  
  725.    if (i != cpstn)
  726.    {
  727.     s = (char) ((fdata[i] >> 15) ^ invfla );
  728.  
  729.   /* add in new number of cycles to clock  */  clk += (fdata[i] &
  730. 0x7fff);  xct = exc + dto2;  /* exc is current boundary */  while ( clk
  731. >= xct )  {  frame_sync(s);  clk = clk - dt;  }  /* clk now holds new
  732. boundary position. update exc slowly... */  /* 0.005 sucks; 0.02 better;
  733. 0.06 mayber even better; 0.05 seems pretty good */  exc = exc +
  734. 0.050*(clk - exc);
  735.  
  736.     i++;
  737.     if( i >buflen) i = 0;
  738.  
  739.     /* If we are sitting on an active channel and the dotting sequence */
  740.     /* is detected, we should switch back to the control channel       */
  741.     if ( (mode == 1) && (dotting > 0))
  742.     {
  743.       set_freak(chan[control]);
  744.       mode = 0;
  745.       dotting = 0;
  746.       i = cpstn;
  747.     }
  748.    }
  749.  
  750.   }
  751.  
  752.   outportb (0x21, n);          /* disable IRQ interrupt              */
  753.   setvect (irqv, oldfuncc);    /* restore old COM Vector             */
  754.  
  755.   gotoxy(1,23);
  756.   printf("\n");
  757. }
  758.  
  759.